home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume3 / send < prev    next >
Encoding:
Text File  |  1989-02-03  |  24.6 KB  |  1,233 lines

  1. Path: xanth!mcnc!gatech!bloom-beacon!mit-eddie!ll-xn!ames!necntc!ncoast!allbery
  2. From: ag@elgar.UUCP (Keith Gabryelski)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i057: send, reply, shout, huh, stom -- For SysV.
  5. Summary: source for send program.
  6. Message-ID: <183@elgar.UUCP>
  7. Date: 15 Jun 88 22:55:56 GMT
  8. Sender: allbery@ncoast.UUCP
  9. Reply-To: ag@elgar.UUCP (Keith Gabryelski)
  10. Organization: Elgar Corporation, San Diego, CA
  11. Lines: 1219
  12. Approved: allbery@ncoast.UUCP
  13.  
  14. comp.sources.misc: Volume 3, Issue 57
  15. Submitted-By: "Keith Gabryelski" <ag@elgar.UUCP>
  16. Archive-Name: send
  17.  
  18. Here is source code for a send program written under Sco Xenix 2.2.1.
  19. Also included is code for fsend (fast send) and its ilk, huh (display
  20. last send), and stom (send format to unix mailbox format converter).
  21.  
  22. There should be no problem using this code on any system V machine.
  23.  
  24. This code will not work on a BSD machine.  Although it wouldn't be
  25. much work to port it.
  26.  
  27. Send me your comments and bug reports/fixes.
  28.  
  29. It's public domain... Your mileage may vary.
  30.  
  31. --- 
  32.   "If green is all there is to be, then green is good enough for me" - ktf
  33. [  Keith   ]  UUCP: {ucsd, cbosgd!crash, sdcsvax!crash, nosc!crash}!elgar!ag
  34. [Gabryelski]  INET: ag@elgar.cts.com                 ARPA: elgar!ag@ucsd.edu
  35. ----------------------------------------------------------------------------
  36. #! /bin/sh
  37. # This is a shell archive, meaning:
  38. # 1. Remove everything above the #! /bin/sh line.
  39. # 2. Save the resulting text in a file.
  40. # 3. Execute the file with /bin/sh (not csh) to create the files:
  41. #    README
  42. #    Makefile
  43. #    send.c
  44. #    huh.c
  45. #    stom.c
  46. #    doc
  47. # This archive created: Wed Jun 15 15:43:13 1988
  48. export PATH; PATH=/bin:$PATH
  49. if test -f 'README'
  50. then
  51.     echo shar: will not over-write existing file "'README'"
  52. else
  53. cat << \SHAR_EOF > 'README'
  54. To make this package:
  55.  
  56.     edit the Makefile -- change $(BINDIR) and $(MANDIR) to something
  57.                      reasonable.
  58.     make
  59.     make install
  60.  
  61. Voila'
  62. --- 
  63. [  Keith   ]  UUCP: {ucsd, cbosgd!crash, sdcsvax!crash, nosc!crash}!elgar!ag
  64. [Gabryelski]  INET: ag@elgar.cts.com                 ARPA: elgar!ag@ucsd.edu
  65. SHAR_EOF
  66. fi # end of overwriting check
  67. if test -f 'Makefile'
  68. then
  69.     echo shar: will not over-write existing file "'Makefile'"
  70. else
  71. cat << \SHAR_EOF > 'Makefile'
  72. SHELL=/bin/sh
  73. BINDIR = /u/local/bin
  74. MANDIR= /usr/man/man.LOCAL
  75.  
  76. all: send huh stom
  77.  
  78. send:    send.c
  79.     cc -O send.c -o send
  80.  
  81. huh:    huh.c
  82.     cc -O huh.c -o huh
  83.  
  84. stom:    stom.c
  85.     cc -O stom.c -o stom
  86.  
  87. shar:
  88.     shar README Makefile send.c huh.c stom.c doc > send.shar
  89.  
  90. install:
  91.     -rm -f $(BINDIR)/fs $(BINDIR)/fsend $(BINDIR)/fr $(BINDIR)/freply
  92.     -rm -f $(BINDIR)/reply $(BINDIR)/shout $(BINDIR)/send
  93.     cp send huh stom $(BINDIR)
  94.     ln $(BINDIR)/send $(BINDIR)/fs
  95.     ln $(BINDIR)/send $(BINDIR)/fsend
  96.     ln $(BINDIR)/send $(BINDIR)/fr
  97.     ln $(BINDIR)/send $(BINDIR)/freply
  98.     ln $(BINDIR)/send $(BINDIR)/reply
  99.     ln $(BINDIR)/send $(BINDIR)/shout
  100.     -cp doc/*.C $(MANDIR)
  101.  
  102. lint:
  103.     lint send.c -o send
  104. SHAR_EOF
  105. fi # end of overwriting check
  106. if test -f 'send.c'
  107. then
  108.     echo shar: will not over-write existing file "'send.c'"
  109. else
  110. cat << \SHAR_EOF > 'send.c'
  111. /*
  112. **  send.c
  113. **
  114. **    Written by: Keith Gabryelski (ag@elgar.UUCP)
  115. **
  116. **        Released into public domain June 14, 1988.
  117. **            Please keep this header.
  118. */
  119.  
  120. #include <stdio.h>
  121. #include <sys/types.h>
  122. #include <sys/stat.h>
  123. #include <utmp.h>
  124. #include <pwd.h>
  125. #include <errno.h>
  126.  
  127. extern errno;
  128.  
  129. extern struct passwd *getpwuid(), *getpwnam();
  130.  
  131. extern FILE *fopen();
  132. extern char *getlogin(), *strrchr(), *ctime(), *malloc(), *realloc();
  133. extern char *ttyname(), *strcpy(), *strncpy(), *strcat();
  134. extern long time();
  135.  
  136. extern char *sys_errlist[];
  137. extern int sys_nerr;
  138. extern void setutent();
  139.  
  140. #undef TRUE
  141. #undef FALSE
  142. #define TRUE            1
  143. #define FALSE            0
  144. #define UNUSED            -1
  145.  
  146. #define NORMAL            0
  147. #define FAST            1
  148.  
  149. #define    SENDS_FILENAME        "/.sends"    /* must have the '/' */
  150. #define    DEAD_SEND_FILENAME    "/dead.send"    /* must have the '/' */
  151.  
  152. #define MESSAGE_SEPARATOR    0x1F
  153.  
  154. char *puterr(), *get_typed_message(), *cat_message(), *myfgets();
  155. char *get_last_sender();
  156. int reply(), send(), shout();
  157.  
  158. struct
  159. {
  160.     char *name;                /* Command name.    */
  161.     int (*function)();            /* Function to use.    */
  162.     int type;                /* Parameters.        */
  163.     char *text;                /* First word in header.*/
  164. }
  165. command_table[] =
  166. {
  167.     {"fr", reply, FAST, "Reply"},
  168.     {"freply", reply, FAST, "Reply"},
  169.     {"fs", send, FAST, "Message"},
  170.     {"fsend", send, FAST, "Message"},
  171.     {"reply", reply, NORMAL, "Reply"},
  172.     {"send", send, NORMAL, "Message"},
  173.     {"shout", shout, NORMAL, "Shout"},
  174.     {NULL, }
  175. };
  176.  
  177. int argc, uid;
  178. char **argv, *progname;
  179. char login_name[] = "        \0",        /* eight chars plus nul */
  180.      tty_name[] = "            \0";        /* twelve chars plus a nul */
  181.  
  182. char *
  183. mymalloc(size)
  184. unsigned size;
  185. {
  186.     char *p;
  187.  
  188.     if ((p = malloc(size)) == NULL)
  189.     {
  190.     (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  191.     exit(-1);
  192.     }
  193.  
  194.     return p;
  195. }
  196.  
  197. char *
  198. myrealloc(p, size)
  199. char *p;
  200. unsigned size;
  201. {
  202.     if (p == NULL)
  203.     {
  204.     if ((p = malloc(size)) == NULL)
  205.     {
  206.         (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  207.         exit(-1);
  208.     }
  209.     }
  210.     else if ((p = realloc(p, size)) == NULL)
  211.     {
  212.     (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  213.     exit(-1);
  214.     }
  215.  
  216.     return p;
  217. }
  218.  
  219. main(largc, largv)
  220. int largc;
  221. char **largv;
  222. {
  223.     char *ptr;
  224.     int i;
  225.     struct passwd *pt;
  226.  
  227.     progname = *largv++;  --largc;
  228.     argv = largv;  argc = largc;
  229.  
  230.     uid = getuid();
  231.  
  232.     pt = getpwuid(uid);
  233.  
  234.     if ((ptr = getlogin()) == NULL)
  235.     if ((ptr = pt->pw_name) == NULL)
  236.         ptr = "somebody";        /* can't figure this guy out */
  237.  
  238.     (void) strncpy(login_name, ptr, 8);
  239.  
  240.     if ((ptr = ttyname(0)) == NULL)
  241.     strcpy(tty_name, "tty??");
  242.     else
  243.     strncpy(tty_name, ((ptr= strrchr(ptr, '/')) ? ptr+1 : "tty??"), 12);
  244.  
  245.     i = 0;
  246.     while (command_table[i].name != NULL)
  247.     if (strcmp(progname, command_table[i].name))
  248.         ++i;
  249.     else
  250.         break;
  251.  
  252.     if (command_table[i].name == NULL)
  253.     send(NORMAL, "Message");
  254.     else
  255.     (*command_table[i].function)(command_table[i].type,
  256.                      command_table[i].text);
  257.  
  258.     exit(0);
  259. }
  260.  
  261. /*
  262. ** reply --
  263. **           Reply to a previously sent message.  This routine uses the
  264. **           (from) user name of the last message sent as the user to
  265. **           send a message to.
  266. */
  267.  
  268. reply(type, text)
  269. int type;
  270. char *text;
  271. {
  272.     char **send_to_list = (char **)mymalloc(0);
  273.     char *message;
  274.  
  275.     /*
  276.     ** make send_to_list initially have one element -- NULL.
  277.     **
  278.     ** Even though only one user is ever gonna get a message,
  279.     ** I still use the add_to_list() routine.
  280.     */
  281.  
  282.     send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
  283.     send_to_list[0] = NULL;
  284.  
  285.     add_to_list(&send_to_list, get_last_sender());
  286.  
  287.     message = get_typed_message();
  288.  
  289.     send_message(send_to_list, message, type, text);
  290. }
  291.  
  292. /*
  293. ** send - generic send-a-message-to-one-or-more-users routine.
  294. **
  295. **
  296. **
  297. */
  298.  
  299. send(type, text)
  300. int type;
  301. char *text;
  302. {
  303.     char **send_to_list = (char **)mymalloc(0);
  304.     char *message;
  305.  
  306.     /*
  307.     ** make send_to_list initially have one element -- NULL.
  308.     **
  309.     */
  310.  
  311.     send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
  312.     send_to_list[0] = NULL;
  313.  
  314.     if (argc < 1)
  315.     {
  316.     fprintf(stderr, "%s: usage: %s user1, [user2,] [...,] [message]\n",
  317.         progname, progname);
  318.     exit(-1);
  319.     }
  320.  
  321.     while (*argv != NULL)
  322.     {
  323.     --argc;
  324.     if ((*argv)[strlen(*argv)-1] == ',')
  325.     {
  326.         (*argv)[strlen(*argv)-1] = '\0';
  327.         add_to_list(&send_to_list, *argv++);
  328.     }
  329.     else
  330.     {
  331.         add_to_list(&send_to_list, *argv++);
  332.         break;
  333.     }
  334.     }
  335.  
  336.     message = get_typed_message();
  337.  
  338.     send_message(send_to_list, message, type, text);
  339. }
  340.  
  341. /*
  342. ** shout -- Send a message to all logged in users.
  343. **
  344. **
  345. */
  346.  
  347. shout(type, text)
  348. int type;
  349. char *text;
  350. {
  351.     char **send_to_list = (char **)mymalloc(0);
  352.     char *message;
  353.     struct utmp *getutent(), *ut;
  354.  
  355.     /*
  356.     ** make send_to_list initially have one element -- NULL.
  357.     **
  358.     */
  359.  
  360.     send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
  361.     send_to_list[0] = NULL;
  362.  
  363.     setutent();
  364.  
  365.     while ((ut = getutent()) != (struct utmp *)NULL)
  366.     if (ut->ut_type == USER_PROCESS)
  367.         add_to_list(&send_to_list, ut->ut_line);
  368.  
  369.     message = get_typed_message();
  370.  
  371.     send_message(send_to_list, message, type, text);
  372. }
  373.  
  374. /*
  375. ** get_typed_message() --
  376. **                         Get arguments for a message of the command line
  377. **                         and take input from stdin if the last argument
  378. **                         is "-" or no message was given on the command
  379. **                         line.
  380. */
  381.  
  382. char *
  383. get_typed_message()
  384. {
  385.     char *buffer = mymalloc(1);
  386.     int old_argc;
  387.  
  388.     *buffer = '\0';
  389.  
  390.     old_argc = argc;
  391.     while (argc > 0 && !(argc == 1 && !strcmp(*argv, "-")))
  392.     {
  393.     buffer = cat_message(buffer, *argv++);
  394.     buffer = cat_message(buffer, " ");
  395.     --argc;
  396.     }
  397.  
  398.     if (argc || !old_argc)
  399.     {
  400.     char *line = mymalloc(BUFSIZ);
  401.  
  402.     while ((line = myfgets(line, BUFSIZ, stdin)) != NULL)
  403.         buffer = cat_message(buffer, line);
  404.     }
  405.  
  406.     /*
  407.     ** That extra <cr> or ' '. ack...
  408.     */
  409.  
  410.     if (buffer[strlen(buffer)-1] == '\n' || buffer[strlen(buffer)-1] == ' ')
  411.     buffer[strlen(buffer)-1] = '\0';
  412.  
  413.     return buffer;
  414. }
  415.  
  416. char *
  417. myfgets(buffer, size, stream)
  418. char *buffer;
  419. int size;
  420. FILE *stream;
  421. {
  422.     int c, length = 0;
  423.  
  424.     while ((c = getc(stream)) != EOF && c != '\n' && (length-1) < size)
  425.     if (c >= ' ')
  426.         buffer[length++] = c;
  427.  
  428.     if (c == '\n')
  429.     buffer[length++] = c;
  430.  
  431.     buffer[length++] = '\0';
  432.  
  433.     return  c == EOF ? NULL : buffer;
  434. }
  435.  
  436. char *
  437. cat_message(buffer, line)
  438. char *buffer, *line;
  439. {
  440.     buffer = myrealloc(buffer, strlen(buffer) + strlen(line) + 1);
  441.     strcat(buffer, line);
  442.     return buffer;
  443. }
  444.  
  445. char *
  446. get_last_sender()
  447. {
  448.     char *ptr, *sends_filename = mymalloc(0);
  449.     char dummy[50];
  450.     static char name[50];
  451.     int c, n;
  452.     struct passwd *pt;
  453.     FILE *fp;
  454.  
  455.     pt = getpwuid(uid);
  456.  
  457.     if ((ptr = pt->pw_dir) != NULL)
  458.     {
  459.     sends_filename = myrealloc(sends_filename, strlen(ptr) +
  460.                    sizeof(SENDS_FILENAME) + 1);
  461.  
  462.     strcpy(sends_filename, ptr);
  463.     strcat(sends_filename, SENDS_FILENAME);
  464.  
  465.     if ((fp = fopen(sends_filename, "r")) == (FILE *)NULL)
  466.     {
  467.         fprintf(stderr, "%s: No reply possible, can't open %s (%s).\n",
  468.             progname, sends_filename, puterr(errno));
  469.         exit(-1);
  470.     }
  471.  
  472.     *name = '\0';
  473.     while (fscanf(fp, "[%s %s %s (%s", dummy, dummy, dummy,
  474.                name) == 4)
  475.         while ((c = getc(fp)) != MESSAGE_SEPARATOR && c != EOF)
  476.         ;
  477.  
  478.     fclose(fp);
  479.  
  480.     if (name[strlen(name)-1] == ')')
  481.         name[strlen(name)-1] = '\0';
  482.  
  483.     if (*name == '\0')
  484.     {
  485.         fprintf(stderr, "%s: no sends.\n", progname);
  486.         exit(-1);
  487.     }
  488.     }
  489.     else
  490.     {
  491.     fprintf(stderr, "%s: No reply possible, no home directory.\n",
  492.         progname);
  493.  
  494.     exit(-1);
  495.     }
  496.  
  497.     return name;
  498. }
  499.  
  500. send_message(user_list, message, type, text)
  501. char **user_list, *message;
  502. int type;
  503. char *text;
  504. {
  505.     char *date_text, *ptr, *sends_filename = mymalloc(0);
  506.     char **sent_to_list = (char **)mymalloc(0);
  507.     char **sends_list = (char **)mymalloc(0);
  508.     int sendit = TRUE, sent = FALSE, failed = FALSE, need_crlf = FALSE;
  509.     long clock[1];
  510.     struct utmp *getutent(), *ut;
  511.     struct passwd *pt;
  512.     struct stat stbuf;
  513.     FILE *fp;
  514.     static char device[] = "/dev/            \0";
  515.  
  516.     /* setup null sent_to_list */
  517.  
  518.     sent_to_list = (char **)myrealloc(sent_to_list, sizeof(char *));
  519.     sent_to_list[0] = NULL;
  520.  
  521.     sends_list = (char **)myrealloc(sends_list, sizeof(char *));
  522.     sends_list[0] = NULL;
  523.  
  524.     /* get the date without a terminating <cr> */
  525.  
  526.     clock[0] = time((long *)0);
  527.     date_text = ctime(clock);
  528.     date_text[24] = '\0';
  529.  
  530.     /* find user/tty in utmp */
  531.  
  532.     while (*user_list != NULL)
  533.     {
  534.     setutent();
  535.     sendit = UNUSED;
  536.     sent = FALSE;
  537.  
  538.     while ((ut = getutent()) != (struct utmp *)NULL)
  539.     {
  540.         if ((ut->ut_type == USER_PROCESS) &&
  541.         ((!strncmp(ut->ut_user, *user_list, 8)) ||
  542.          (!strncmp(ut->ut_line, *user_list, 12))))
  543.         {
  544.         sendit = TRUE;
  545.  
  546.         if (add_to_list(&sent_to_list, ut->ut_line))
  547.         {
  548.             sent = TRUE;
  549.             break;
  550.         }
  551.  
  552.         strncpy(device+5, ut->ut_line, 12);
  553.  
  554.         if (uid != 0)
  555.         {
  556.             if (stat(device, &stbuf) == -1)
  557.             {
  558.             fprintf(stderr, "%s: Couldn't stat %s (%s).\n",
  559.                 progname, device, puterr(errno));
  560.             sendit = FALSE;
  561.             failed = TRUE;
  562.             }
  563.             else
  564.             if (!stbuf.st_mode&2)
  565.             {
  566.                 fprintf(stderr,
  567.                     "[%s/%s]: Is not receiving sends.\n",
  568.                     ut->ut_user, ut->ut_line);
  569.                 sendit = FALSE;
  570.                 failed = TRUE;
  571.             }
  572.         }
  573.  
  574.         /* open device and send the message */
  575.  
  576.         if (sendit)
  577.         {
  578.             if ((fp = fopen(device, "w")) == (FILE *)NULL)
  579.             fprintf(stderr, "%s: could not open %s (%s).\n",
  580.                 progname, device, puterr(errno));
  581.             else
  582.             {
  583.             if (type&FAST)
  584.                 fprintf(fp, "\007\n[%s/%s: %s]\n", login_name,
  585.                     tty_name, message);
  586.             else
  587.                 fprintf(fp, "\007\n[%s from %s (%s) %s]\n%s\n",
  588.                     text, login_name, tty_name, date_text,
  589.                     message);
  590.  
  591.             printf("[%s/%s] ", ut->ut_user, ut->ut_line);
  592.  
  593.             need_crlf = sent = TRUE;
  594.  
  595.             fclose(fp);
  596.  
  597.             /* write send to ~user/.sends file */
  598.             if (!add_to_list(&sends_list, ut->ut_user))
  599.             {
  600.                 pt = getpwnam(ut->ut_user);
  601.  
  602.                 if ((ptr = pt->pw_dir) != NULL)
  603.                 {
  604.                 sends_filename =
  605.                     myrealloc(sends_filename, strlen(ptr) +
  606.                           sizeof(SENDS_FILENAME) + 1);
  607.  
  608.                 strcpy(sends_filename, ptr);
  609.                 strcat(sends_filename, SENDS_FILENAME);
  610.  
  611.                 if ((fp = fopen(sends_filename, "a+")) !=
  612.                     (FILE *)NULL)
  613.                     fprintf(fp, "[%s from %s (%s) %s]\n%s\n%c",
  614.                         text, login_name, tty_name,
  615.                         date_text, message,
  616.                         MESSAGE_SEPARATOR);
  617.  
  618.                 fclose(fp);
  619.                 }
  620.             }
  621.             }
  622.         }
  623.         }
  624.     }
  625.  
  626.     if (!sent)
  627.     {
  628.         failed = TRUE;
  629.         if (sendit == UNUSED)
  630.         {
  631.         /*
  632.         ** Decide what the user tried to type in.  Was it a user
  633.         ** who isn't logged in or maybe a tty device that no user
  634.         ** is logged on to or maybe a mistyped username.
  635.         */
  636.  
  637.         if ((pt = getpwuid(*user_list)) == (struct passwd *)NULL)
  638.         {
  639.             int status;
  640.  
  641.             strncpy(device+5, *user_list, 12);
  642.  
  643.             status = stat(device, &stbuf);
  644.  
  645.             if (status == -1 || !stbuf.st_mode&S_IFCHR)
  646.             fprintf(stderr, "%s: no user %s.\n", progname,
  647.                 *user_list);
  648.             else
  649.             fprintf(stderr, "%s: no user logged on device %s.\n",
  650.                 progname, *user_list);
  651.         }
  652.         else
  653.             fprintf(stderr, "%s: %s not logged in.\n", progname,
  654.                 *user_list);
  655.         }
  656.     }
  657.     ++user_list;
  658.     }
  659.  
  660.     if (failed)
  661.     {
  662.     char *dead_filename = malloc(0);
  663.  
  664.     pt = getpwuid(uid);
  665.  
  666.     if ((ptr = pt->pw_dir) == NULL)
  667.     {
  668.         dead_filename = myrealloc(dead_filename, sizeof("/tmp/") +
  669.                       sizeof(login_name) + 
  670.                       sizeof(DEAD_SEND_FILENAME) + 1);
  671.  
  672.         strcpy(dead_filename, "/tmp/");
  673.         strcat(dead_filename, login_name);
  674.         strcat(dead_filename, DEAD_SEND_FILENAME);
  675.     }
  676.     else
  677.     {
  678.         dead_filename = myrealloc(dead_filename, strlen(ptr) +
  679.                        sizeof(DEAD_SEND_FILENAME) + 1);
  680.         strcpy(dead_filename, ptr);
  681.         strcat(dead_filename, DEAD_SEND_FILENAME);
  682.     }
  683.  
  684.     if ((fp = fopen(dead_filename, "a+")) != (FILE *)NULL)
  685.     {
  686.         fprintf(fp, "[%s from %s (%s) %s]\n%s\n%c", text, login_name,
  687.             tty_name, date_text, message, MESSAGE_SEPARATOR);
  688.  
  689.         fprintf(stderr, "%s: message copied to %s.\n", progname,
  690.             dead_filename);
  691.         
  692.     }
  693.  
  694.     fclose(fp);
  695.     free(dead_filename);
  696.     }
  697.  
  698.     if (need_crlf)
  699.     putchar('\n');
  700.  
  701.     free(sends_filename);
  702. }
  703.  
  704. add_to_list(list, name)
  705. char ***list, *name;
  706. {
  707.     register int i;
  708.  
  709.     for (i = 0; (*list)[i] != NULL; ++i)
  710.     if (!strcmp((*list)[i], name))
  711.         return TRUE;
  712.  
  713.     *list = (char **)myrealloc(*list, sizeof(char *) * (i + 2));
  714.     (*list)[i] = mymalloc(strlen(name)+1);
  715.     strcpy((*list)[i], name);
  716.     (*list)[i+1] = NULL;
  717.  
  718.     return FALSE;
  719. }
  720.  
  721. /*
  722. **
  723. **free_list(list)
  724. **char **list;
  725. **{
  726. **    register int i;
  727. **
  728. **    for (i = 0; list[i] != NULL; ++i)
  729. **    free(list[i]);
  730. **
  731. **    free(list);
  732. **}
  733. */
  734.  
  735. char *
  736. puterr(error)
  737. int error;
  738. {
  739.     static char qwerty[42];
  740.  
  741.     (void) sprintf(qwerty, "Unknown error %d", error);
  742.  
  743.     return ((unsigned)error >= sys_nerr) ? qwerty : sys_errlist[error];
  744. }
  745. SHAR_EOF
  746. fi # end of overwriting check
  747. if test -f 'huh.c'
  748. then
  749.     echo shar: will not over-write existing file "'huh.c'"
  750. else
  751. cat << \SHAR_EOF > 'huh.c'
  752. /*
  753. **  huh.c --
  754. **        What was that last send?
  755. **
  756. **    Written by: Keith Gabryelski (ag@elgar.UUCP)
  757. **
  758. **        Released into public domain June 14, 1988.
  759. **            Please keep this header.
  760. */
  761.  
  762. #include <stdio.h>
  763. #include <sys/types.h>
  764. #include <sys/stat.h>
  765. #include <pwd.h>
  766. #include <errno.h>
  767.  
  768. extern errno;
  769.  
  770. extern FILE *fopen();
  771. extern struct passwd *getpwuid(), *getpwnam();
  772. extern char *sys_errlist[], *malloc(), *realloc();
  773. extern int sys_nerr;
  774.  
  775. #undef TRUE
  776. #undef FALSE
  777. #define TRUE            1
  778. #define FALSE            0
  779.  
  780. #define    SENDS_FILENAME        "/.sends"    /* must have the '/' */
  781. #define MESSAGE_SEPARATOR    0x1F
  782.  
  783. char *puterr(), *mymalloc(), *myrealloc();
  784. char *progname;
  785.  
  786. int sflag = FALSE;
  787.  
  788. char *
  789. mymalloc(size)
  790. unsigned size;
  791. {
  792.     char *p;
  793.  
  794.     if ((p = malloc(size)) == NULL)
  795.     {
  796.     (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  797.     exit(-1);
  798.     }
  799.  
  800.     return p;
  801. }
  802.  
  803. char *
  804. myrealloc(p, size)
  805. char *p;
  806. unsigned size;
  807. {
  808.     if (p == NULL)
  809.     {
  810.     if ((p = malloc(size)) == NULL)
  811.     {
  812.         (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  813.         exit(-1);
  814.     }
  815.     }
  816.     else if ((p = realloc(p, size)) == NULL)
  817.     {
  818.     (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  819.     exit(-1);
  820.     }
  821.  
  822.     return p;
  823. }
  824.  
  825. main(argc, argv)
  826. int argc;
  827. char **argv;
  828. {
  829.     char *ptr, *sends_filename = mymalloc(0);
  830.     int amount = 1, n, c;
  831.     long *seek_list = (long *)mymalloc(0);
  832.     struct passwd *pt;
  833.     FILE *fp;
  834.  
  835.     progname = *argv++;  --argc;
  836.  
  837.     if (**argv == '-')
  838.     if (!strcmp(*argv, "-s"))
  839.     {
  840.         sflag = TRUE;
  841.         *++argv; --argc;
  842.     }
  843.     else
  844.     {
  845.         fprintf(stderr, "%s: invalid switch given.\n", progname);
  846.         usage();
  847.     }
  848.  
  849.     if (argc > 2)
  850.     usage();
  851.  
  852.     if (argc)
  853.     {
  854.     amount = atoi(*argv++);
  855.     --argc;
  856.     }
  857.  
  858.     if (amount < 1)
  859.     {
  860.     fprintf(stderr, "%s: invalid amount.\n", progname);
  861.     usage();
  862.     }
  863.  
  864.     if (argc)
  865.     {
  866.     if ((pt = getpwnam(*argv)) == (struct passwd *)NULL)
  867.     {
  868.         fprintf(stderr, "%s: invalid user name '%s'.\n", progname, *argv);
  869.         exit(-1);
  870.     }
  871.     }
  872.     else
  873.     pt = getpwuid(getuid());
  874.  
  875.     if ((ptr = pt->pw_dir) == NULL)
  876.     {
  877.     fprintf(stderr, "%s: couldn't find a home directory.\n", progname);
  878.     exit(-1);
  879.     }
  880.  
  881.     sends_filename = myrealloc(sends_filename, strlen(ptr) +
  882.                    sizeof(SENDS_FILENAME) + 1);
  883.  
  884.     strcpy(sends_filename, ptr);
  885.     strcat(sends_filename, SENDS_FILENAME);
  886.  
  887.     if ((fp = fopen(sends_filename, "r")) == (FILE *)NULL)
  888.     {
  889.     if (errno == ENOENT)
  890.     {
  891.         fprintf(stderr, "No sends.\n");
  892.         exit(0);
  893.     }
  894.     else
  895.     {
  896.         fprintf(stderr, "%s: couldn't open sends file %s (%s).\n",
  897.             progname, sends_filename, puterr(errno));
  898.         exit(-1);
  899.     }
  900.     }
  901.  
  902.     /* setup null sent_to_list */
  903.  
  904.     seek_list = (long *)myrealloc(seek_list, sizeof(long));
  905.     seek_list[0] = -1;
  906.  
  907.     do
  908.     {
  909.     n = add_to_list(&seek_list, ftell(fp));
  910.  
  911.     while((c = getc(fp)) != MESSAGE_SEPARATOR && c != EOF)
  912.         ;
  913.     } while (c != EOF);
  914.  
  915.     if (n == 1)
  916.     fprintf(stderr, "No sends.\n");
  917.     else
  918.     {
  919.     if (n-1 < amount)
  920.         amount = 0;
  921.     else
  922.         amount = n - amount - 1;
  923.  
  924.     fseek(fp, seek_list[amount], 0);
  925.  
  926.     do
  927.     {
  928.         while ((c = getc(fp)) != MESSAGE_SEPARATOR && c != EOF)
  929.         putchar(c);
  930.  
  931.         if (sflag && c == MESSAGE_SEPARATOR)
  932.         putchar(MESSAGE_SEPARATOR);
  933.     } while (c != EOF);
  934.     }
  935.     
  936.     fclose(fp);
  937.  
  938.     exit(0);
  939. }
  940.  
  941. usage()
  942. {
  943.     fprintf(stderr, "%s: usage %s [-s] [amount] [username]\n", progname,
  944.         progname);
  945.     exit(-1);
  946. }
  947.  
  948. add_to_list(list, element)
  949. long **list, element;
  950. {
  951.     register int i;
  952.  
  953.     for (i = 0; (*list)[i] != -1; ++i)
  954.     ;
  955.  
  956.     *list = (long *)myrealloc(*list, sizeof(long) * (i + 2));
  957.     (*list)[i] = element;
  958.     (*list)[i+1] = -1;
  959.  
  960.     return i+1;
  961. }
  962.  
  963. char *
  964. puterr(error)
  965. int error;
  966. {
  967.     static char qwerty[42];
  968.  
  969.     (void) sprintf(qwerty, "Unknown error %d", error);
  970.  
  971.     return ((unsigned)error >= sys_nerr) ? qwerty : sys_errlist[error];
  972. }
  973. SHAR_EOF
  974. fi # end of overwriting check
  975. if test -f 'stom.c'
  976. then
  977.     echo shar: will not over-write existing file "'stom.c'"
  978. else
  979. cat << \SHAR_EOF > 'stom.c'
  980. /*
  981. **  stom.c --
  982. **        Convert a .sends formatted message into a Unix mailbox
  983. **        format.
  984. **
  985. **    Written by: Keith Gabryelski (ag@elgar.UUCP)
  986. **
  987. **        Released into public domain June 14, 1988.
  988. **            Please keep this header.
  989. */
  990.  
  991. #include <stdio.h>
  992. #include <sys/types.h>
  993. #include <sys/stat.h>
  994. #include <pwd.h>
  995. #include <errno.h>
  996.  
  997. extern errno;
  998.  
  999. extern FILE *fopen();
  1000. extern struct passwd *getpwuid(), *getpwnam();
  1001. extern char *sys_errlist[], *malloc(), *realloc();
  1002. extern int sys_nerr;
  1003.  
  1004. #undef TRUE
  1005. #undef FALSE
  1006. #define TRUE            1
  1007. #define FALSE            0
  1008.  
  1009. #define    SENDS_FILENAME        "/.sends"    /* must have the '/' */
  1010. #define MESSAGE_SEPARATOR    0x1F
  1011.  
  1012. char *puterr(), *mymalloc(), *myrealloc();
  1013. char *progname;
  1014.  
  1015. main(argc, argv)
  1016. int argc;
  1017. char **argv;
  1018. {
  1019.     FILE *fp;
  1020.  
  1021.     progname = *argv++; --argc;
  1022.  
  1023.     if (argc < 1)
  1024.     convert(stdin);
  1025.     else
  1026.     while (argc--)
  1027.     {
  1028.         if ((fp = fopen(*argv, "r")) == NULL)
  1029.         fprintf(stderr, "%s: can't access file %s (%s).\n", progname,
  1030.             *argv, puterr(errno));
  1031.         else
  1032.         convert(fp);
  1033.  
  1034.         *++argv;
  1035.     }
  1036.  
  1037.     exit(0);
  1038. }
  1039.  
  1040. convert(stream)
  1041. FILE *stream;
  1042. {
  1043.     char text[20], user_name[10], date[28];
  1044.     char *dp;
  1045.     int c;
  1046.  
  1047.     while (fscanf(stream, "[%s from %s ", text, user_name) == 2)
  1048.     {
  1049.     /*
  1050.     ** ignore tty.
  1051.     */
  1052.     while ((c = getc(stream)) != ')')
  1053.         ;
  1054.  
  1055.     /*
  1056.     ** get date.
  1057.     */
  1058.  
  1059.     dp = date;
  1060.  
  1061.     while ((c = getc(stream)) != ']')
  1062.         *dp++ = c;
  1063.  
  1064.     *dp = '\0';
  1065.  
  1066.     printf("From %s%s\nSubject: A %s\n",  user_name, date, text);
  1067.  
  1068.     /*
  1069.     ** And the message itself.
  1070.     */
  1071.     while ((c = getc(stream)) != MESSAGE_SEPARATOR)
  1072.         putchar(c);
  1073.     }
  1074. }
  1075.  
  1076. char *
  1077. puterr(error)
  1078. int error;
  1079. {
  1080.     static char qwerty[42];
  1081.  
  1082.     (void) sprintf(qwerty, "Unknown error %d", error);
  1083.  
  1084.     return ((unsigned)error >= sys_nerr) ? qwerty : sys_errlist[error];
  1085. }
  1086. SHAR_EOF
  1087. fi # end of overwriting check
  1088. if test ! -d 'doc'
  1089. then
  1090.     mkdir 'doc'
  1091. fi
  1092. cd 'doc'
  1093. if test -f 'send.C'
  1094. then
  1095.     echo shar: will not over-write existing file "'send.C'"
  1096. else
  1097. cat << \SHAR_EOF > 'send.C'
  1098. .TH SEND C
  1099. .SH NAME
  1100. send, fsend, fs, reply, freply, fr, shout \- send a message to one or more
  1101. users on the system.
  1102. .SH SYNOPSIS
  1103. .B send
  1104. user1[, user2][, user3][,... ][message]
  1105.  
  1106. .B fsend
  1107. user1[, user2][, user3][,... ][message]
  1108.  
  1109. .B fs
  1110. user1[, user2][, user3][,... ][message]
  1111.  
  1112. .B reply
  1113. [message]
  1114.  
  1115. .B freply
  1116. [message]
  1117.  
  1118. .B fr
  1119. [message]
  1120.  
  1121. .B shout
  1122. [message]
  1123. .SH DESCRIPTION
  1124.  
  1125. Send (and its counterparts) display messages on a specified user (or
  1126. users) terminal(s).
  1127.  
  1128. Send (and fsend) take a comma separated list of usernames (or tty
  1129. devices) to send the message to.  If a message is given on the command
  1130. line, it may be continued (via stdin) by putting a dash as the last
  1131. argument on the command line.  If no message is specified, stdin will
  1132. be used.
  1133.  
  1134. Reply will use the username of the last person to send you a message
  1135. as the recipient of the current message.
  1136.  
  1137. Fsend and freply use shorter headers to cutdown on message output.
  1138. They work exactly like their counterparts (send and reply) in all
  1139. other respects.
  1140.  
  1141. Shout will send a message to all users on the system.  Not for regular
  1142. use.
  1143.  
  1144. As a message is sent to user, it is also written to a save file called
  1145. ".sends" in the recipients home directory.  This file must exist and should
  1146. be 622 mode for it to be updated correctly.  This file is typically
  1147. cleared on logout.
  1148.  
  1149. Fs and fr are finger savers for fsend and freply.
  1150. .SH FILES
  1151. ~USERNAME/.sends    - Sends save file.
  1152. ~/dead.send        - Save file for failed sends.
  1153. .SH SEE ALSO
  1154. huh(C), stom(C)
  1155. .SH AUTHOR
  1156. .RS
  1157. .PP
  1158. Keith M. Gabryelski (ag@elgar.UUCP)
  1159. .RE
  1160. SHAR_EOF
  1161. fi # end of overwriting check
  1162. if test -f 'huh.C'
  1163. then
  1164.     echo shar: will not over-write existing file "'huh.C'"
  1165. else
  1166. cat << \SHAR_EOF > 'huh.C'
  1167. .TH HUH C
  1168. .SH NAME
  1169. huh \- Display last send.
  1170. .SH SYNOPSIS
  1171. .B huh
  1172. [-s] [amount] [username]
  1173. .SH DESCRIPTION
  1174. Huh will display the last 
  1175. .B amount
  1176. (default; 1)
  1177. send message(s) from the user 
  1178. .B username
  1179. (default; your own) .sends file.
  1180.  
  1181. -s is used to format the output of huh(C) into something stom(C) can
  1182. use as input.
  1183. .SH FILES
  1184. ~USERNAME/.sends    - Sends save file.
  1185. .SH SEE ALSO
  1186. send(C), stom(C)
  1187. .SH AUTHOR
  1188. .RS
  1189. .PP
  1190. Keith M. Gabryelski (ag@elgar.UUCP)
  1191. .RE
  1192. SHAR_EOF
  1193. fi # end of overwriting check
  1194. if test -f 'stom.C'
  1195. then
  1196.     echo shar: will not over-write existing file "'stom.C'"
  1197. else
  1198. cat << \SHAR_EOF > 'stom.C'
  1199. .TH STOM C
  1200. .SH NAME
  1201. stom \- convert a .sends formatted file to a unix mailbox format.
  1202. .SH SYNOPSIS
  1203. .B stom
  1204. [file1] [file2] [file3] [...]
  1205. .SH DESCRIPTION
  1206. Stom converts a .sends formatted file into a unix mailbox format.  If
  1207. no arguments are given stom will use stdin.
  1208.  
  1209. This is useful when used in conjuction with huh(C) to reply via mail
  1210. to a send.
  1211.  
  1212. .RS
  1213. huh -s | stom > mailbox
  1214. .PP
  1215. mail -f mailbox
  1216. .RE
  1217. .SH SEE ALSO
  1218. huh(C), send(C)
  1219. .SH AUTHOR
  1220. .RS
  1221. .PP
  1222. Keith M. Gabryelski (ag@elgar.UUCP)
  1223. .RE
  1224. SHAR_EOF
  1225. fi # end of overwriting check
  1226. cd ..
  1227. #    End of shell archive
  1228. exit 0
  1229. -- 
  1230.   "If green is all there is to be, then green is good enough for me" - ktf
  1231. [  Keith   ]  UUCP: {ucsd, cbosgd!crash, sdcsvax!crash, nosc!crash}!elgar!ag
  1232. [Gabryelski]  INET: ag@elgar.cts.com                ARPA: elgar!ag@ucsd.edu
  1233.